/*
 *  Utils.h
 *  NSE_SOLVER
 *
 *  Created by Patrick Zulian on 12/22/10.
 *  Copyright 2010 ICS - USI - Lugano. All rights reserved.
 *
 */


#ifndef __UTILS_UTILS_H__
#define __UTILS_UTILS_H__


#include <iostream>
#include <stdio.h>
#include <time.h>
#include <string>
#include <vector>

#include "Base.h"

///General useful utilities for arrays, random numbers, stl components
namespace utils {
	
	
	/**
	 *Resets the random generator given the time 
	 */
	inline
	void TimeSRand()	
	{
		srand( static_cast< unsigned int >(time(0)) );
	}
    

    inline 
    void SRand(unsigned int seed)
    {
        srand(seed);
    }
	
	/**
	 *@return a double between 0 and 1
	 */
	inline	
	double Rand()
	{
		return static_cast< double >( rand() ) / static_cast< double >(RAND_MAX);
	}
	
	/**
	 *copies an array of type T to dest
	 *@param src
	 *@param dest
	 *@param D size of the arrays
	 */
	template<typename T, int D>
	void Copy(T * dest, const T src[]) 
	{
		memcpy(dest, src, sizeof(T)*D);
	}
	
	
	/**
	 *copies an array of type T to dest
	 *@param src
	 *@param dest
	 *@param D size of the arrays
	 */
	template<typename T>
	void Copy(T * dest, const T src[], int D) 
	{
		memcpy(dest, src, sizeof(T)*D);
	}
	
	
	
		
	/** 
	 * @tparam T is the numeric type
	 * @tparam MULTIPLE is the upper-bound multiple 
	 * @param number is the number for which we want the upper-bound
	 * @return the upper bound of number
	 */
	template<typename T, T MULTIPLE>
	const T GetUpperBound(const T number) {
		assert(MULTIPLE > 1);
		T upperBound = MULTIPLE;
		while (upperBound < number) {
			upperBound *= MULTIPLE;
		}
		return upperBound;
	}
	
	
	/**
	 *@param src the 2D matrix
	 *@param dest the 2D matrix
	 *@param m number of rows
	 *@param n number of columns
	 */
	template<typename T>
	static void
	MatrixCopy(T ** src, T ** dest, const int m, const int n) {
		int iter;
		for (iter = 0; iter < m; iter++) {
			Copy(src[iter], dest[iter], n);
		}	
	}
	
	/**
	 *@param arr[OUT] the array that will be initialize to 0
	 *@param size the size of the array
	 */
	template<typename T>
	static void 
	Zeros(T * arr, const int size);
	
	
	/**
	 *@param arr[OUT] the array that will be initialize to 0
	 *@param size the size of the array
	 */
	template <> 
	inline void Zeros(int *arr, const int size)
	{
		memset(arr, 0, size*sizeof(int));
	}
	
	/**
	 *@param arr[OUT] the array that will be initialize to val
	 *@param val the initial value
	 *@param size the extent of the array
	 */
	template<typename T>
	static void InitArray(T *arr, const T val, const int size)
	{
		int iter;
		for (iter = 0; iter < size; iter++) {
			arr[iter] = val;
		}
	}
	
	
	
	
	/**
	 *@param a[IN] the array that will be printed
	 *@param size the extent of the array
	 */
	template<typename T>
	static void PrintArray(T * a, const int size) 
	{
		int iter;
		for (iter = 0;  iter < size; iter++) {
			std::cout <<"arr[" << iter <<"] = "<< a[iter] <<std::endl;	
		}
		
	}
	
	/**
	 *@param[IN] arr the input array
	 *@param size the extent
	 *@return the sum of all elements of the array
	 */
	template<typename T>
	static T SumArray(T * arr, const int size)
	{
		int iter;
		T sum = arr[0];
		for (iter = 1; iter < size; iter++) {
			sum += arr[iter];
		}
		return sum;
	}
	
	/**
	 *@param src[IN] the input array
	 *@param target[OUT] input and output array
	 *@param size the extent
	 */
	template<typename T>
	static void SumArrays(T * src, T * target, const int size)
	{
		int iter;
		for (iter = 0; iter < size; iter++) {
			target[iter] += src[iter];
		}
		
	}
	
	/**
	 *@param[IN] arr the input array
	 *@param size the extent
	 *@return the multiplication of all elements of the array
	 */
	template<typename T>
	static T MulArray(T * arr, const int size)
	{
		
		T sum = arr[0];
		
		int iter;
		for (iter = 1; iter < size; iter++) {
			sum *= arr[iter];
		}
		return sum;
	}
	
	
	/**
	 * \brief Allows to compare object pointers in a STL container. The object are required to have a compare(T) :  -1 | 0 | 1 method 
	 * -1 left is less than right, 0 equal, 1 right is less than left 
	 *@tparam T is a pointer to some object thus T = *Type
	 *@param left the object that calls compare on the right
	 *@param right the object passed to compare
	 *@return true if left->compare(right) < 0 else false
	 */
	template<typename T >
	struct PComparator {
		bool operator() (const T  &left, const T  &right) const 
		{ 
			const int val = left->compare(right);
			return val < 0; 
		}
	};
	
	/**
	 *	To be used in order to free pointers collected inside a container
	 *	@tparam the container type
	 *	@param c the container object
	 */
	template< typename C >
	void FreeValues(C &c) 
	{
		typename C::iterator it;
		for ( it = c.begin(); it != c.end(); ++it ) {
			delete *it;
		}
	}
	
	/**
	 * Used to print on the stdin the percentace of completenes of a process !!in place!!
	 * @param status the current status of execution
	 * @param finalStatus the status when the process is complete
	 */
	inline
	void PrintPercentage(const int status, const int finalStatus)
	{
		const int distance = finalStatus - status;
		const double ratio = ((double)status)/((double)finalStatus);
		if (distance == 0) {
			printf("\b\b\b\b\b[%s] ", "complete");
		} else if (distance == finalStatus) {
			printf("[%d%%] ", 0);
			fflush(stdout);
		} else if (ratio < 0.1) {
			printf("\b\b\b\b\b[%d%%] ", (int) ( ratio * 100.0));
			fflush(stdout);
		} else {
			printf("\b\b\b\b\b[%d%%]", (int) ( ratio * 100.0));
			fflush(stdout);
		}
	}
	
	
	template< typename TO, typename FROM >
	TO Parse(const FROM &value);
	
	//template<>
	static inline
	double Parse/*< double, char >*/(const char * value)
	{
		return (double) atof(value);
	}
	
	
	static
	const std::vector< std::string > SplitString(const std::string &inputString, const char parseChar = '\t')
	{
		std::vector< std::string > subStrings;
		
		int previous = 0;
		int next =  inputString.find(parseChar, previous);
		
		while (next != -1) {
			subStrings.push_back(inputString.substr(previous, next - previous));
			previous = next + 1;
			next = inputString.find(parseChar, previous);
		}
		if(previous < (int) inputString.length())
			subStrings.push_back(inputString.substr(previous,  inputString.length()));
		
		return subStrings;
	}
	
	template< typename T >
	const std::vector< T > SplitAndParseString(const std::string &inputString, const char parseChar = '\t') 
	{
		
		std::vector< std::string > strings = SplitString(inputString, parseChar);
		std::vector< T > result;
		
		for (std::vector< std::string >::iterator it = strings.begin(); it != strings.end(); ++it) {
			result.push_back(Parse(it->c_str()));
		}
		
		return result;
	}
	
	
}

#endif
